package com.triones.framework.common.rule;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.*;

/**
 * 规则定义
 *
 * @author triones
 */
@Slf4j
public class BooleanJavaScriptEngineRule {

    private String supportExpr;
    private String executeExpr;

    public BooleanJavaScriptEngineRule(String supportExpr, String executeExpr) {
        this.supportExpr = supportExpr;
        this.executeExpr = executeExpr;
    }

    public boolean support(Map context) {
        if (StringUtils.isBlank(supportExpr)) {
            return true;
        } else {
            Boolean b = (Boolean) eval(supportExpr, context);
            return b != null && b;
        }
    }

    public Map execute(Map context) {
        Object eval = eval(executeExpr, context);
        if (eval == null) {
            return null;
        }
        return JSONUtil.parse(eval).toBean(Map.class);
    }

    public Boolean executeSupport(Map context) {
        if (StringUtils.isBlank(executeExpr)) {
            return true;
        } else {
            return (Boolean) eval(executeExpr, context);
        }
    }

    private Object eval(String expr, Map<String, Object> context) {
        try {
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("JavaScript");
            Bindings bindings = engine.createBindings();
            bindings.putAll(context);
            Object eval = engine.eval(expr, bindings);
            return eval;
        } catch (Exception e) {
            log.error("fail to execute expression " + expr, e);
            return null;
        }
    }

    public static void main(String[] args) {
        long timesC = 0L;
        long start = System.currentTimeMillis();
        System.out.println(start);
        for (int i = 1; i <= 100; i++) {
            for (int j = 0; j <= 1; j++) {
                Map map = new HashMap();
                map.put("ZAZHI", i);
                map.put("HANSHUI", j);
                BooleanRuleExprValue rD = new BooleanRuleExprValue("ZAZHI > 15.00 || HANSHUI > 25.00", 1, map, "D");
                BooleanRuleExprValue rC = new BooleanRuleExprValue("ZAZHI <= 15.00 && ZAZHI > 10.00 || HANSHUI <= 25 && HANSHUI > 20", 2, map, "C");
                BooleanRuleExprValue rB = new BooleanRuleExprValue("ZAZHI <= 10.00 && ZAZHI > 5 || HANSHUI <= 20.00 && HANSHUI > 10", 3, map, "B");
                BooleanRuleExprValue rA = new BooleanRuleExprValue("ZAZHI >= 0.00 && ZAZHI <= 5 && HANSHUI <= 10 && HANSHUI >= 0", 4, map, "A");

                List<BooleanRuleExprValue> sortedList = new ArrayList<>();
                sortedList.add(rB);
                sortedList.add(rC);
                sortedList.add(rD);
                sortedList.add(rA);
                Collections.sort(sortedList, Comparator.naturalOrder());
                BooleanRuleExprValue resultTrue = validFirstTrue(sortedList);
                if (resultTrue == null) {
                    throw new RuntimeException("存在无法计算值");
                }
                System.out.println(resultTrue.toString());
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end);
        timesC = end - start;
        System.out.println(timesC);
    }

    public static BooleanRuleExprValue validFirstTrue(List<BooleanRuleExprValue> exprStrArr) {
        for (BooleanRuleExprValue booleanRuleExprValue : exprStrArr) {
            BooleanJavaScriptEngineRule booleanJavaScriptEngineRule = new BooleanJavaScriptEngineRule(Convert.toStr(booleanRuleExprValue.getExpr()), Convert.toStr(booleanRuleExprValue.getExpr()));
            if (booleanJavaScriptEngineRule.executeSupport(booleanRuleExprValue.getParams())) {
                booleanRuleExprValue.setResult(true);
                return booleanRuleExprValue;
            }
        }
        return null;
    }
}
